﻿/**************************************************************
 *
 * 唯一标识：1846d38e-d41d-4d1f-93ef-c5cebca33390
 * 命名空间：Sgr.OrganizationAggregate
 * 创建时间：2023/8/2 11:29:14
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using Sgr.Domain.Entities;
using Sgr.Domain.Entities.Auditing;
using Sgr.Exceptions;
using System;
using System.Threading.Tasks;
using Sgr.Domain.Repositories;
using Sgr.UPMS.Events;

namespace Sgr.UPMS.Domain.Organizations
{
    /// <summary>
    /// 组织机构
    /// </summary>
    public class Organization : FullAudited<long, long>, IAggregateRoot, IOptimisticLock, IExtendableObject, ITreeNode<long>, IHaveCode
    {
        /// <summary>
        /// 缓冲期天数（默认15天）
        /// </summary>
        private const int RECOVERY_GRACE_PERIOD_DAYS = 15;

        protected Organization()
        { }

        internal Organization(
            string identificationCode,
            string name,
            string staffSizeCode,
            string? remarks)
        {
            IdentificationCode = identificationCode;
            Name = name;
            StaffSizeCode = staffSizeCode;
            Remarks = remarks;

            Code = Guid.NewGuid().ToString("N").ToUpper();
            Confirmed = ConfirmedStates.WaitingConfirmed;
            State = EntityStates.Normal;
        }

        /// <summary>
        /// 组织机构名称
        /// </summary>
        public string Name { get; private set; } = string.Empty;

        /// <summary>
        /// 人员规模编码
        /// </summary>
        public string StaffSizeCode { get; set; } = string.Empty;

        /// <summary>
        /// 描述
        /// </summary>
        public string? Remarks { get; set; }

        /// <summary>
        /// Logo地址
        /// </summary>
        public string? LogoUrl { get; set; }

        /// <summary>
        /// 组织机构编码（默认情况下，选用统一社会信用代码）
        /// </summary>
        public string Code { get; internal protected set; } = string.Empty;

        /// <summary>
        /// 组织机构识别码（默认情况下，是由系统自动生成的6位字符编码）
        /// </summary>
        public string IdentificationCode { get; private set; } = string.Empty;

        /// <summary>
        /// 组织机构类型编码
        /// </summary>
        public string OrgTypeCode { get; set; } = string.Empty;

        /// <summary>
        /// 所属行政区划编码（默认情况下，选用邮政编码）
        /// </summary>
        public string AreaCode { get; set; } = string.Empty;

        /// <summary>
        /// 机构负责人/联系人
        /// </summary>
        public string? Leader { get; set; }

        /// <summary>
        /// 联系电话
        /// </summary>
        public string? Phone { get; set; }

        /// <summary>
        /// 联系邮箱
        /// </summary>
        public string? Email { get; set; }

        /// <summary>
        /// 所在地址
        /// </summary>
        public string? Address { get; set; }

        /// <summary>
        /// 营业执照路径
        /// </summary>
        public string? BusinessLicensePath { get; internal set; }

        /// <summary>
        /// 组织机构认证状态
        /// </summary>
        public ConfirmedStates Confirmed { get; internal set; } = ConfirmedStates.WaitingConfirmed;

        /// <summary>
        /// 组织机构排序号
        /// </summary>
        public int OrderNumber { get; set; } = 0;

        /// <summary>
        /// 组织机构状态
        /// </summary>
        public EntityStates State { get; private set; } = EntityStates.Deactivate;

        /// <summary>
        /// 上次注销时间（用于计算恢复期）
        /// </summary>
        public DateTime? LastCancellationTime { get; private set; }

        /// <summary>
        /// 是否在恢复期内
        /// </summary>
        public bool IsInRecoveryPeriod => LastCancellationTime.HasValue &&
            DateTime.UtcNow < LastCancellationTime.Value.AddDays(RECOVERY_GRACE_PERIOD_DAYS);

        /// <summary>
        /// 获取剩余恢复天数
        /// </summary>
        /// <returns>如果不在恢复期内返回null，否则返回剩余天数</returns>
        public double? GetRemainingRecoveryDays()
        {
            if (!LastCancellationTime.HasValue || !IsInRecoveryPeriod)
                return null;

            var remainingTime = LastCancellationTime.Value.AddDays(RECOVERY_GRACE_PERIOD_DAYS) - DateTime.UtcNow;
            return Math.Round(remainingTime.TotalDays, 1);
        }

        /// <summary>
        /// 组织注销
        /// </summary>
        public void Cancellation()
        {
            if (this.State == EntityStates.Deactivate)
                return;

            // 执行注销相关的领域逻辑
            this.State = EntityStates.Deactivate;
            this.LastCancellationTime = DateTime.UtcNow;  // 记录注销时间

            // 触发注销事件
            this.AddDomainEvent(new OrganizationCancellationDomainEvent(this.Id, true));
        }

        /// <summary>
        /// 尝试恢复组织
        /// </summary>
        /// <returns>恢复是否成功</returns>
        public bool TryRecover()
        {
            // 检查是否需要恢复
            if (this.State != EntityStates.Deactivate || !LastCancellationTime.HasValue)
                return false;

            // 检查是否在恢复期内
            if (!IsInRecoveryPeriod)
            {
                throw new DomainException($"组织已超出恢复期限。恢复期截止时间：{LastCancellationTime.Value.AddDays(RECOVERY_GRACE_PERIOD_DAYS):yyyy-MM-dd HH:mm:ss}");
            }

            // 执行恢复
            this.State = EntityStates.Normal;
            this.LastCancellationTime = null;  // 清除注销时间

            // 触发恢复事件
            this.AddDomainEvent(new OrganizationCancellationDomainEvent(this.Id, false));

            return true;
        }

        /// <summary>
        /// 调整组织名称
        /// </summary>
        /// <param name="name"></param>
        public void ChangeName(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return;

            if (this.Name != name)
            {
                this.Name = name.Trim();
                this.AddDomainEvent(new OrganizationNameChangedDomainEvent(this.Id));
            }
        }

        #region ITreeNode (树形结构)

        /// <summary>
        /// 改变父
        /// </summary>
        /// <param name="parentId"></param>
        /// <param name="nodePath"></param>
        internal void SetParent(long parentId, string nodePath)
        {
            if (ParentId != parentId)
            {
                this.ParentId = parentId;
            }

            this.NodePath = nodePath;
        }

        /// <summary>
        /// 上级组织Id
        /// </summary>
        public long ParentId { get; private set; } = 0;

        /// <summary>
        /// 树节点层次目录
        /// </summary>
        public string NodePath { get; private set; } = string.Empty;

        #endregion ITreeNode (树形结构)

        #region IOptimisticLock (乐观锁)

        /// <summary>
        /// 行版本
        /// </summary>
        public long RowVersion { get; set; }

        #endregion IOptimisticLock (乐观锁)

        #region IExtendableObject (定义一个JSON格式的字符串属性来扩展对象/实体)

        /// <summary>
        /// 扩展信息
        /// </summary>
        public string? ExtensionData { get; set; }

        #endregion IExtendableObject (定义一个JSON格式的字符串属性来扩展对象/实体)

        //#region IMustHaveOrg  (如果一个实体实现该接口，那么必须存储实体所在组织的ID.)

        ///// <summary>
        ///// 所属组织
        ///// </summary>
        //public long OrgId { get; internal protected set; }

        //#endregion

        #region 业务规则

        ///// <summary>
        ///// 改变组织机构状态
        ///// </summary>
        ///// <param name="state"></param>
        //public void ChangeEntityState(EntityStates state)
        //{
        //}

        /// <summary>
        /// 是否为顶级组织
        /// </summary>
        /// <returns></returns>
        public bool IsRoot()
        {
            return ParentId == 0;
        }

        #endregion 业务规则
    }
}